package org.inasnet.audio;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.*;

import org.inasnet.BytesPack;
import org.inasnet.Root;


public class Playback implements Runnable 
{
	SourceDataLine line;
    Thread thread;
	double duration;
    //boolean playNext = false;
    
    public AudioInputStream audioInputStream;
    
    String errStr;
    
    Playback()
    {
    }

    void start()
    {
        errStr = null;
        thread = new Thread(this);
        thread.setName("Playback");
        thread.start();
    }

    void stop()
    {
        thread = null;
    }
    
    private void shutDown(String message, Exception e )
    {
    	if( e != null ) 
    		e.printStackTrace();
    	/*
    	System.out.println("errStr");
        if ((errStr = message) != null)
        {
            System.err.println(errStr);
        }*/
        if (thread != null)
        {
            thread = null;
        } 
    }

    public void run()
    {
		///*
        // define the required attributes for our line, 
        // and make sure a compatible line is supported.
        
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, AudioManager.format);
        if (!AudioSystem.isLineSupported(info))
        {
            shutDown("Line matching " + info + " not supported.", null );
            return;
        }
		
        // get and open the source data line for playback.
		
		try
        {
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open( AudioManager.format, AudioManager.bufSize );
        }
        catch (LineUnavailableException ex)
        { 
            shutDown("Unable to open the line: ", ex);
            return;
        }
		
        // play back the captured audio data
		
		int frameSizeInBytes = AudioManager.format.getFrameSize();
        int bufferLengthInFrames = line.getBufferSize() / 8;
        int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
        byte[] data = new byte[bufferLengthInBytes];
        int numBytesRead = 0;
		
        // start the source data line
        line.start();
            
        while (thread != null)
    	{
        	BytesPack pack = null;
        	
    		try
    		{
    			while( pack == null ) 
    			{
    				thread.sleep( 1 );
    				
    				pack = AudioManager.getSessionInputStream().poolPack();
    				
    				//Root.log ( "get " + pack );
    			}
    		}
    		catch( Exception e )
    		{
    			
    		}
    		
    		// load bytes into the audio input stream for playback
    		//byte audioBytes[] = out.toByteArray();
    		//out.reset();
	          		
    		
    		ByteArrayInputStream bais = new ByteArrayInputStream( pack.bytes, 0, pack.size );
    	    audioInputStream = new AudioInputStream( bais, AudioManager.format, pack.size / frameSizeInBytes);

        	long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / AudioManager.format.getFrameRate());
        	duration = milliseconds / 1000.0;
    		
			// make sure we have something to play
            if (audioInputStream == null)
            {
               	shutDown("No loaded audio to play back", null );
            	//e.printStackTrace();
               	return;
            }
            // reset to the beginnning of the stream
            try
            {
              	audioInputStream.reset();
	        }
    	    catch (Exception e)
    	    {
    	    	shutDown("Unable to reset the stream\n", e);
    	        //return;
    	    	//e.printStackTrace();
    	    }
    	    
    	    AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(AudioManager.format, audioInputStream);
    	    
    	    if (playbackInputStream == null)
    	    {
    	        shutDown("Unable to convert stream of format " + audioInputStream + " to format " + AudioManager.format, null );
    	    	//e.printStackTrace();
    	    	return;
    	    }
    	    
			//System.out.println("Playing started " + pack.size );
			
            while (thread != null)
            {
                try
                {
                    if ((numBytesRead = playbackInputStream.read(data)) == -1)
                    {
                        break;
                    }
                    int numBytesRemaining = numBytesRead;
                    while (numBytesRemaining > 0 )
                    {
                        numBytesRemaining -= line.write(data, 0, numBytesRemaining);
                    }
                }
                catch (Exception e)
                {
                    shutDown("Error during playback: ", e);
                	//e.printStackTrace();
                    break;
                }
            }
        }
        audioInputStream = null;
        // we reached the end of the stream.  let the data play out, then
        // stop and close the line.
        if (thread != null)
        {
            line.drain();
        }
        line.stop();
        line.close();
        line = null;
        shutDown( "end", null);
        
        //*/
        
    }      
}
